﻿using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace GLDotNet.WinForms
{
    [Category("GLDotNet")]
    [Description("Custom WinForms control which provides a GLContext.")]
    public class GLControl : Control
    {   
        private static GLContextParams? contextParams;
        private static bool firstControlCreated;

        GLContext context;
        GLContextEventArgs contextEventArgs;

        public static GLContextParams? ContextParams
        {
            get { return contextParams; }

            set
            {
                if (firstControlCreated)
                    throw new InvalidOperationException("GLControl.ContextParams can only be set before the first GLControl is created.");

                contextParams = value;
            }
        }

        /// <summary>
        /// The DesignMode property does not correctly tell you if
        /// you are in design mode.  IsDesignerHosted is a corrected
        /// version of that property.
        /// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
        /// and http://decav.com/blogs/andre/archive/2007/04/18/1078.aspx )
        /// </summary>
        public bool IsDesignerHosted
        {
            get
            {
                Control ctrl = this;

                while (ctrl != null)
                {
                    if ((ctrl.Site != null) && ctrl.Site.DesignMode)
                        return true;

                    ctrl = ctrl.Parent;
                }

                return false;
            }
        }

        public event EventHandler<GLContextEventArgs> ContextCreated;

        public event EventHandler<GLContextEventArgs> Render;

        public GLControl()
            : base()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.BackColor = System.Drawing.Color.CornflowerBlue;
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();

            if (!this.IsDesignerHosted)
            {
                if (contextParams == null)
                    throw new InvalidOperationException("GLControl.ContextParams must be set before the first GLControl is created.");

                this.context = new GLContext(new WGLContext(contextParams.Value, this.Handle));

                this.contextEventArgs = new GLContextEventArgs(this.context);

                firstControlCreated = true;

                if (this.ContextCreated != null)
                    this.ContextCreated(this, this.contextEventArgs);
            }
        }
                
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (this.context != null)
            {
                this.context.Dispose();
                this.context = null;
            }
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            // Overridden to prevent flickering.

            if (this.IsDesignerHosted)
            {
                base.OnPaintBackground(pevent);
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (!this.IsDesignerHosted)
            {
                if (this.context.MakeCurrent())
                {
                    this.OnRender(this.contextEventArgs);

                    this.context.SwapBuffers();
                }
            }
        }

        protected virtual void OnRender(GLContextEventArgs e)
        {
            if (this.Render != null)
                this.Render(this, e);
        }
    }
}
